import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.*;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FilenameUtils;

/**
 * Servlet implementation class UploadServlet
 */
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet
{

    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    File tmpDir = null;
    File saveDir = null;

    public UploadServlet()
    {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        // TODO Auto-generated method stub
        doPost(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException
    {
        // TODO Auto-generated method stub
        try
        {
            PrintWriter out = response.getWriter();
            out.println("<html><body>");

            if (ServletFileUpload.isMultipartContent(request))
            {
                DiskFileItemFactory dff = new DiskFileItemFactory();
                dff.setRepository(tmpDir);
                dff.setSizeThreshold(1024000);
                ServletFileUpload sfu = new ServletFileUpload(dff);
                sfu.setFileSizeMax(1024 * 1024 * 20); // filesize
                sfu.setSizeMax(1024 * 1024 * 40); // totalsize
                List<FileItem> items = sfu.parseRequest(request);

                String command = null, filename = null;
                int port = -1;
                for (FileItem item : items)
                {
                    if (item.isFormField() && item.getFieldName().equals("command"))
                    {
                        command = item.getString();
                    }
                    else if (item.isFormField() && item.getFieldName().equals("port"))
                    {
                        port = Integer.parseInt(item.getString());
                    }
                }

                for (FileItem item : items)
                {
                    if (!item.isFormField())
                    {
                        filename = FilenameUtils.getName(item.getName());
                        boolean portInUse = false;
                        for (Application app : Metadata.getInstance().getApps())
                        {
                            if (app.port == port)
                            {
                                out.println("Port " + port + " already in use. <br />");
                                portInUse = true;
                                break;
                            }
                        }

                        if (!portInUse)
                        {
                            File savedApp = new File(saveDir, filename);

                            InputStream filecontent = item.getInputStream();
                            BufferedInputStream fin = new BufferedInputStream(filecontent);
                            BufferedOutputStream fout = new BufferedOutputStream(new FileOutputStream(savedApp));

                            int n;
                            byte[] buffer = new byte[1024];
                            while ((n = fin.read(buffer)) != -1)
                            {
                                fout.write(buffer, 0, n);
                            }
                            fout.flush();
                            fout.close();
                            fin.close();

                            for (ComputeNode cn : Metadata.getInstance().getComputeNodes().values())
                            {
                                Socket soc = new Socket(cn.hostname, FileTransferer.fileport);
                                FileTransferer.send(soc, savedApp, command);
                                soc.close();
                            }

                            Metadata.getInstance().getApps().add(new Application(filename, command, port));
                            new Thread(new Dispatcher(port)).start();

                            out.println("File upload successfully! <br />");
                        }
                    }
                }

                out.println("<a href=\"/\">Back to home</a>");
                out.println("</body></html>");
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public void init() throws ServletException
    {
        /*
         * Initialize
         */
        super.init();
        String tmpPath = "/home/ubuntu/Test/tmp";
        String savePath = "/home/ubuntu/apps";
        tmpDir = new File(tmpPath);
        saveDir = new File(savePath);
        if (!tmpDir.isDirectory())
            tmpDir.mkdir();
        if (!saveDir.isDirectory())
            saveDir.mkdir();
    }
}
